package com.chenfan.mcn.controller;

import cn.afterturn.easypoi.excel.ExcelImportUtil;
import cn.afterturn.easypoi.excel.entity.ImportParams;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.chenfan.common.exception.BusinessException;
import com.chenfan.common.vo.UserVO;
import com.chenfan.mcn.clients.baseinfo.BaseInfoClient;
import com.chenfan.mcn.clients.privilege.PrivilegeClient;
import com.chenfan.mcn.clients.privilege.SUserVo;
import com.chenfan.mcn.config.UserVoContextHolder;
import com.chenfan.mcn.constant.McnConstant;
import com.chenfan.mcn.constant.NumberCst;
import com.chenfan.mcn.enums.DiscountApprovalEnum;
import com.chenfan.mcn.enums.ApprovalStatusEnum;
import com.chenfan.mcn.exception.McnErrorCode;
import com.chenfan.mcn.extension.Res;
import com.chenfan.common.extension.validation.groups.Add;
import com.chenfan.common.extension.validation.groups.Modify;
import com.chenfan.mcn.model.DiscountApproval;
import com.chenfan.mcn.model.McnPage;
import com.chenfan.mcn.model.dto.ApprovalConditionallyDTO;
import com.chenfan.mcn.model.dto.DiscountDTO;
import com.chenfan.mcn.model.dto.DiscountHistoryDTO;
import com.chenfan.mcn.model.dto.DiscountApprovalSearchDTO;
import com.chenfan.mcn.model.vo.DiscountApprovalRelationVO;
import com.chenfan.mcn.model.vo.DiscountApprovalVO;
import com.chenfan.mcn.model.vo.DiscountInfoVO;
import com.chenfan.mcn.service.DiscountApprovalService;
import com.chenfan.mcn.extension.excel.ExcelUtils;
import com.chenfan.mcn.utils.CommonUtil;
import com.chenfan.privilege.common.config.SearchAuthority;
import com.chenfan.privilege.common.config.UrlAuth;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.DateUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import springfox.documentation.annotations.ApiIgnore;

import javax.servlet.http.HttpServletResponse;
import javax.validation.constraints.NotNull;
import java.math.BigDecimal;
import java.text.ParseException;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 折扣审批单
 * @author lizhejin
 */
@Slf4j
@RestController
@RequestMapping(value = "/discount")
public class DiscountApprovalController {

    @Autowired
    private DiscountApprovalService discountApprovalService;

    @Autowired
    private PrivilegeClient privilegeClient;

    @Autowired
    private BaseInfoClient baseInfoClient;

    private static final String NO_REBATE = "no_rebate";

    /**
     * 折扣审批单
     *
     * @return {@link DiscountApproval}
     */
    @GetMapping(value = "/list")
    @UrlAuth({"discountRebates_search"})
    public Res<Page<DiscountApprovalVO>> getDiscountApprovalList(@ApiIgnore McnPage<DiscountApprovalVO> page, @SearchAuthority DiscountApprovalSearchDTO dto) {
        return Res.ok(discountApprovalService.getDiscountApprovalList(page, dto));
    }


    /**
     * 客户档案关联折扣审批单
     *
     * @param page 分页
     * @param customerId 客户ID
     * @return
     */
    @GetMapping(value = "/relationList")
    public Res<Page<DiscountApprovalRelationVO>> getDiscountApprovalRelationList(@ApiIgnore McnPage<DiscountApprovalRelationVO> page, Long customerId) {
        return Res.ok(discountApprovalService.getDiscountApprovalRelationList(page, customerId));
    }

    /**
     * 获取折扣审批单详情
     *
     * @param id 折扣审批单id
     * @return {@link DiscountDTO}
     */
    @GetMapping(value = "/info")
    public Res<DiscountInfoVO> getDiscountApprovalInfo(Long id) {
        return Res.ok(discountApprovalService.getDiscountApprovalInfo(id));
    }

    /**
     * 新增折扣审批单
     *
     * @param dto {@link DiscountDTO}
     * @return {@link Res}
     */
    @PostMapping(value = "/create")
    @UrlAuth({"discountRebates_add"})
    public Res<Long> saveDiscountApprovalList(@RequestBody @Validated(Add.class) DiscountDTO dto) {
        validateApprovalType(dto);
        UserVO userVO = UserVoContextHolder.getUserVo();
        dto.setUpdateBy(userVO.getUserId());
        dto.setUpdateName(userVO.getRealName());
        dto.setCreateBy(userVO.getUserId());
        dto.setCreateName(userVO.getRealName());
        dto.setCompanyId(userVO.getCompanyId());
        dto.setDepartmentId(userVO.getDepartmentId());
        dto.setTenantId(userVO.getTenantId());
        return Res.ok(discountApprovalService.saveDiscount(dto));
    }

    /**
     * 更新折扣审批单
     *
     * @param dto {@link DiscountDTO}
     * @return {@link Res}
     */
    @PostMapping(value = "/update")
    @UrlAuth({"discountRebates_edit"})
    public Res<Object> updateDiscountApprovalList(@RequestBody @Validated(Modify.class) DiscountDTO dto) {
        validateApprovalType(dto);
        UserVO userVO = UserVoContextHolder.getUserVo();
        dto.setUpdateBy(userVO.getUserId());
        dto.setUpdateName(userVO.getRealName());
        return Res.ok(discountApprovalService.saveDiscount(dto));
    }

    private void validateApprovalType(DiscountDTO dto) {
        if (dto.getApprovalType() == DiscountApprovalEnum.SINGLE_DISCOUNT.code()) {
            if (Objects.isNull(dto.getRebateRate()) && !NO_REBATE.equals(dto.getRebateType())) {
                throw new BusinessException(McnErrorCode.PARAM_ERROR);
            }
            if (Objects.isNull(dto.getContractAmount()) || Objects.isNull(dto.getRebateType()) || Objects.isNull(dto.getDiscountRate())) {
                throw new BusinessException(McnErrorCode.PARAM_ERROR);
            }
        } else if (dto.getApprovalType() == DiscountApprovalEnum.YEAR_DISCOUNT.code()) {
            if (Objects.isNull(dto.getStartDate()) || Objects.isNull(dto.getEndDate()) || Objects.isNull(dto.getDiscountType())
                    || Objects.isNull(dto.getLiveBroadcastStatus())) {
                throw new BusinessException(McnErrorCode.PARAM_ERROR);
            }
            boolean rebate = Objects.isNull(dto.getRebateList()) || dto.getRebateList().isEmpty();
            boolean range = Objects.isNull(dto.getRangeList()) || dto.getRangeList().isEmpty();
            if (DiscountApprovalEnum.rebateCheck(dto.getDiscountType()) && rebate) {
                throw new BusinessException(McnErrorCode.PARAM_ERROR);
            }
            if (DiscountApprovalEnum.rangeCheck(dto.getDiscountType()) && range) {
                throw new BusinessException(McnErrorCode.PARAM_ERROR);
            }
            if (discountApprovalService.checkYearActiveCounts(dto) > 0) {
                throw new BusinessException(McnErrorCode.DATE_RANGE_EXISTS);
            }
        }
    }

    /**
     * 修改折扣审批单状态
     *
     * @param discountApproval {@link DiscountApproval}
     * @return {@link Res}
     */
    @PostMapping(value = "/status/change")
    @UrlAuth({"discountRebates_revocation","discountRebates_cancellation","discountRebates_submit"})
    public Res<Object> changeStatus(@RequestBody DiscountApproval discountApproval) {
        if (Objects.isNull(discountApproval.getId()) || Objects.isNull(discountApproval.getApprovalStatus())) {
            throw new BusinessException(McnErrorCode.PARAM_ERROR);
        }
        DiscountApproval tmp = discountApprovalService.getById(discountApproval.getId());
        if (Objects.isNull(tmp)) {
            throw new BusinessException(McnErrorCode.DISCOUNT_NOT_EXISTS);
        }
        validateStatus(tmp, discountApproval.getApprovalStatus());
        UserVO userVO = UserVoContextHolder.getUserVo();
        tmp.setUpdateBy(userVO.getUserId());
        tmp.setUpdateDate(new Date());
        tmp.setUpdateName(userVO.getRealName());
        tmp.setApprovalStatus(discountApproval.getApprovalStatus());
        return discountApprovalService.changeStatus(tmp) ? Res.ok() : Res.failed();
    }

    @SuppressWarnings("AlibabaAvoidComplexCondition")
    private void validateStatus(DiscountApproval discountApproval, Integer status) {
        if (discountApproval.getApprovalStatus() == ApprovalStatusEnum.UN_COMMIT.code() &&
                (status != ApprovalStatusEnum.APPROVAL.code() && status != ApprovalStatusEnum.INVALID.code())) {
            throw new BusinessException(McnErrorCode.DISCOUNT_APPROVAL_UN_COMMIT_COMMIT_ERROR);
        }
        if (discountApproval.getApprovalStatus() == ApprovalStatusEnum.APPROVAL.code() &&
                (status != ApprovalStatusEnum.CANCEL.code() && status != ApprovalStatusEnum.INVALID.code())) {
            throw new BusinessException(McnErrorCode.DISCOUNT_APPROVAL_UN_COMMIT_CANCEL_ERROR);
        }
        if (discountApproval.getApprovalStatus() == ApprovalStatusEnum.REJECTED.code() &&
                (status != ApprovalStatusEnum.APPROVAL.code() && status != ApprovalStatusEnum.INVALID.code())) {
            throw new BusinessException(McnErrorCode.DISCOUNT_APPROVAL_REJECTED_ERROR);
        }
        if (discountApproval.getApprovalStatus() == ApprovalStatusEnum.CANCEL.code() &&
                (status != ApprovalStatusEnum.APPROVAL.code() && status != ApprovalStatusEnum.INVALID.code())) {
            throw new BusinessException(McnErrorCode.DISCOUNT_APPROVAL_CANCEL_ERROR);
        }
        if (discountApproval.getApprovalStatus() == ApprovalStatusEnum.PASSED.code() &&
                status != ApprovalStatusEnum.INVALID.code()) {
            throw new BusinessException(McnErrorCode.DISCOUNT_APPROVA_PASSED_ERROR);
        }
        if (discountApproval.getApprovalStatus().equals(ApprovalStatusEnum.INVALID.code())) {
            throw new BusinessException(McnErrorCode.DISCOUNT_INVALID);
        }
        if (status.equals(ApprovalStatusEnum.PASSED.code()) || status.equals(ApprovalStatusEnum.REJECTED.code())) {
            if (discountApproval.getApprovalStatus().equals(ApprovalStatusEnum.CANCEL.code())) {
                throw new BusinessException(McnErrorCode.DISCOUNT_CANCELED);
            }
        }
    }

    /**
     * 折扣审批单导出
     *
     * @param dto      过滤参数
     * @param response 响应
     * @throws Exception 导出异常
     */
    @GetMapping(value = "/export")
    @UrlAuth({"discountRebates_export"})
    public void export(@SearchAuthority DiscountApprovalSearchDTO dto, @ApiIgnore HttpServletResponse response) throws Exception {
        dto.setExportStatus(true);
        McnPage<DiscountApprovalVO> page = new McnPage<>();
        page.setPageNum(1).setPageSize(9999);
        List<DiscountApprovalVO> voList = Objects.requireNonNull(discountApprovalService.getDiscountApprovalList(page, dto)).getRecords();
        voList.forEach(discountApprovalVO -> {
            try {
                if (StringUtils.isNotBlank(discountApprovalVO.getStartDate()) && StringUtils.isNotBlank(discountApprovalVO.getEndDate())) {
                    discountApprovalVO.setExportStartDate(DateUtils.parseDate(discountApprovalVO.getStartDate(), McnConstant.LONG_DATE_FORMAT));
                    discountApprovalVO.setExportEndDate(DateUtils.parseDate(discountApprovalVO.getEndDate(), McnConstant.LONG_DATE_FORMAT));
                }
            } catch (ParseException e) {
                log.error("export 时间错误", e);
            }

        });
        ExcelUtils.exportExcel(voList, "折扣审批单", DiscountApprovalVO.class, "折扣审批单.xlsx", response);
    }

    /**
     * 同步历史数据
     * @param file
     * @return
     * @throws Exception
     */
    @PostMapping(value = "/history")
    @Transactional(rollbackFor = Exception.class)
    public Res<Object> synchronous(@RequestPart @NotNull(message = "请上传历史文件") MultipartFile file) throws Exception {
        List<DiscountHistoryDTO> objectList = ExcelImportUtil.importExcel(Objects.requireNonNull(file).getInputStream(), DiscountHistoryDTO.class, new ImportParams());
        List<String> customerList = objectList.stream().map(DiscountHistoryDTO::getCustomer).filter(Objects::nonNull).distinct().collect(Collectors.toList());
        List<String> userList = objectList.stream().map(DiscountHistoryDTO::getCreateBy).filter(Objects::nonNull).distinct().collect(Collectors.toList());
        userList.addAll(objectList.stream().map(DiscountHistoryDTO::getUpdateBy).filter(Objects::nonNull).distinct().collect(Collectors.toList()));
        Map<String, Long> customerMapping = Objects.requireNonNull(baseInfoClient.getCustomerIdByName(customerList)).getObj();
        Map<String, SUserVo> userMapping = Objects.requireNonNull(privilegeClient.getUserIdsByName(userList)).getObj();
        List<String> errorCustomerList = customerList.stream().filter(c -> Objects.isNull(customerMapping.get(c))).collect(Collectors.toList());
        List<String> errorUserList = userList.stream().filter(c -> Objects.isNull(userMapping.get(c))).collect(Collectors.toList());
        List<String> errorDepartmentList = userList.stream().filter(c -> Objects.isNull(userMapping.get(c).getDepartmentId())).collect(Collectors.toList());
        errorUserList.addAll(userList.stream().filter(c -> Objects.isNull(userMapping.get(c))).collect(Collectors.toList()));
        if (errorCustomerList.size() > 0 || errorUserList.size() > 0 || errorDepartmentList.size() > 0) {
            return Res.failed("不存在的客户:" + errorCustomerList.toString() + "///不存在的用户:" + errorUserList.toString() + "///不存在部门的用户:" + errorDepartmentList.toString());
        }
        List<DiscountApproval> discountApprovalList = new ArrayList<>();
        objectList.forEach(o -> {
            DiscountApproval discountApproval = new DiscountApproval();
            if (Objects.isNull(userMapping.get(o.getCreateBy()))) {
                System.out.println(o.getCreateBy());
            }
            discountApproval.setDiscountCode(o.getCode().replaceAll("\t", ""));
            discountApproval.setId(o.getId());
            discountApproval.setCreateName(o.getCreateBy());
            discountApproval.setUpdateName(o.getUpdateBy());
            discountApproval.setDescription(o.getDescription());
            discountApproval.setRemark(o.getRemark());
            discountApproval.setApprovalStatus(o.getStatusName());
            discountApproval.setDiscountRate(o.getDiscountRate() == null ? null : BigDecimal.valueOf(o.getDiscountRate() * 100));
            discountApproval.setContractAmount(o.getPrice() == null ? null : BigDecimal.valueOf(o.getPrice()));
            discountApproval.setRebateRate(o.getRebateRate() == null ? null : BigDecimal.valueOf(o.getRebateRate() * 100));
            discountApproval.setYearDiscountStatus(o.getYear());
            discountApproval.setCreateDate(o.getCreateDate());
            discountApproval.setUpdateDate(o.getUpdateDate());
            discountApproval.setApprovalType(0);
            discountApproval.setRebateType(o.getRebateType() == null ? "corporate_banking" : o.getRebateType().replaceAll("-", "_"));
            discountApproval.setContractSubject(o.getContractSubject());
            discountApproval.setCreateBy(Objects.requireNonNull(userMapping.get(o.getCreateBy())).getUserId());
            discountApproval.setDepartmentId(Objects.requireNonNull(userMapping.get(o.getCreateBy())).getDepartmentId());
            discountApproval.setCompanyId(Objects.requireNonNull(userMapping.get(o.getCreateBy())).getCompanyId());
            discountApproval.setTenantId(Objects.requireNonNull(userMapping.get(o.getCreateBy())).getTenantId());
            discountApproval.setUpdateBy(Objects.requireNonNull(userMapping.get(o.getUpdateBy())).getUserId());
            discountApproval.setCustomerId(customerMapping.get(o.getCustomer()));
            discountApprovalList.add(discountApproval);
        });
        discountApprovalService.saveBatch(discountApprovalList);
        return Res.ok();
    }

    /**
     * 根据合同类型、客户id、是否直播全案获取折扣审批单详情
     *
     * @param approvalConditionallyDTO {@link ApprovalConditionallyDTO}
     * @return {@link DiscountDTO}
     */
    @PostMapping(value = "/getInfo")
    public Res<List<DiscountInfoVO>> getApprovalConditionally(@RequestBody ApprovalConditionallyDTO approvalConditionallyDTO) {
        return Res.ok(discountApprovalService.getApprovalConditionally(approvalConditionallyDTO));
    }


    /**
     * 根据客户id获取关联的折扣审批单
     * @param customerId 客户ID
     * @return
     */
    @GetMapping(value = "/getDiscountApprovals")
    public Res<List<DiscountApprovalVO>> getDiscountApprovals(@RequestParam(required = false) Long customerId) {
        if(Objects.isNull(customerId)) {
            return Res.ok();
        }
        return Res.ok(CommonUtil.defaultList(discountApprovalService.list(Wrappers.lambdaQuery(DiscountApproval.class)
                        .eq(DiscountApproval::getCustomerId, customerId)
                        .eq(DiscountApproval::getApprovalStatus, ApprovalStatusEnum.PASSED.code())
                        .eq(DiscountApproval::getIsDelete, NumberCst.ZERO))
                .stream().map(e -> {
                            DiscountApprovalVO vo = new DiscountApprovalVO();
                            BeanUtils.copyProperties(e, vo);
                            return vo;
                }).collect(Collectors.toList())));
    }
}
